/**********************************************************************************************************************
 *
 * Project:    mGameEngine
 * File:       body.h
 * Author:     twoja stara
 * Created on: 2009-09-25
 *
 **********************************************************************************************************************/

#ifndef BODY_H_
#define BODY_H_

#include "actor.h"

namespace mGameEngine
{
namespace Physics
{

// prototype
class Cloth;

/**
 * Static rigid body.
 * This should be used for creating permanent obstacles and terrain.
 * Each rigid body has specified restitution and friction coefficients.
 */
class Body : public Actor
{
    friend class Cloth;

protected:
    /**
     * Collision shapes.
     */
    List<Shape *> _shapes;

    /**
     * Restitution coefficient (bounciness).
     */
    float _restitution;

    /**
     * Static friction coefficient.
     */
    float _staticFriction;

    /**
     * Dynamic (kinetic) friction coefficient.
     */
    float _dynamicFriction;

    /**
     * PhysX actor.
     */
    mutable NxActor *_actor;

    /**
     * PhysX material.
     */
    mutable NxMaterial *_material;

public:
    /**
     * Create PhysX actor for joint.
     * @param joint joint.
     * @return PhysX actor for joint.
     */
    virtual NxActor *_createJointActor(Joint *joint) const;

protected:
    /**
     * Create PhysX shape descriptor for shape.
     * @param shape shape.
     */
    virtual NxShapeDesc *_createShapeDescriptor(Shape *shape) const;

public:
    /**
     * Create static rigid body.
     */
    Body();

    /**
     * Create static rigid body with specified shape,
     * restitution and friction coefficients.
     * @param shape collision shape.
     * @param restitution (bounciness) coefficient.
     * @param staticFriction static friction coefficient.
     * @param dynamicFriction dynamic (kinetic) friction coefficient.
     */
    Body(Shape *shape, float restitution = 0.5f, float staticFriction = 0.5f, float dynamicFriction = 0.4f);

    /**
     * Destroy static rigid body.
     */
    virtual ~Body();

    /**
     * Get rigid bodys collision shapes.
     * @return rigid body collision shapes.
     */
    const List<Shape *> &getCollisionShapes() const
    {
        return _shapes;
    }

    /**
     * Add collision shape to rigid body.
     * @param shape shape to add.
     */
    virtual void addCollisionShape(Shape *shape);

    /**
     * Remove collision shape from rigid body.
     * @param shape shape to remove.
     */
    virtual void removeCollisionShape(Shape *shape);

    /**
     * Get rigid body restitution coefficient (bounciness).
     * @return rigid body restitution coefficient (bounciness).
     */
    float getRestitution() const
    {
        return _restitution;
    }

    /**
     * Set rigid body restitution coefficient (bounciness).
     * @param restitution restitution coefficient (bounciness).
     */
    void setRestitution(float restitution);

    /**
     * Get rigid body static friction coefficient.
     * @return rigid body static friction coefficient.
     */
    float getStaticFriction() const
    {
        return _staticFriction;
    }

    /**
     * Set rigid body static friction coefficient.
     * @param staticFriction static friction coefficient.
     */
    void setStaticFriction(float staticFriction);

    /**
     * Get rigid body dynamic (kinetic) friction coefficient.
     * @return rigid body dynamic (kinetic) frictin coefficient.
     */
    float getDynamicFriction() const
    {
        return _dynamicFriction;
    }

    /**
     * Set rigid body dynamic (kinetic) friction coefficient.
     * @param dynamicFriction dynamic (kinetic) friction coefficient.
     */
    void setDynamicFriction(float dynamicFriction);

    /**
     * Put force/momentum to static rigid body.
     * This has no effect on static bodies.
     * @param force force vector.
     * @param radius radius at which force is put.
     */
    virtual void putForce(const Vector3 &force, const Vector3 &radius = Vector3());

    /**
     * Put force/momentum impulse to body.
     * This has no effect on static bodies.
     * @param impulse force vector.
     * @param radius radius at which force is put.
     */
    virtual void putImpulse(const Vector3 &impulse, const Vector3 &radius = Vector3());

    /**
     * Put accceleration to body.
     * This has no effect on static bodies.
     * @param acc acceleration vector.
     * @param radius radius at which acceleration is put.
     */
    virtual void putAcceleration(const Vector3 &acc, const Vector3 &radius = Vector3());

    /**
     * Create static rigid body on PhysX scene.
     * @param scene PhysX scene.
     */
    virtual void create(NxScene *scene) const;

    /**
     * Set object connected with body.
     * @param object object connected with body.
     */
    virtual void setConnectedObject(void *object);

    /**
     * Get rigid body transformation.
     * @return rigid body transformation.
     */
    virtual Matrix4x4 getTransformation() const;

    /**
     * Set rigid body transfmoration.
     * @param t transformation.
     */
    virtual void setTransformation(const Matrix4x4 &t);

    /**
     * Get rigid body point linear velocity.
     * @param p rigid body point.
     */
    virtual Vector3 getPointVelocity(const Vector3 &p);
};

}
}

#endif // BODY_H_
